﻿/*
 * protocolcontrolorbase.cpp
 *
 *  Created on: 2017年4月14日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_OS_PROTOCOL DM_API_EXPORT

#include <dm/os/protocol/protocolcontrolor.hpp>

#include <dm/os/protocol/telegram.hpp>
#include <dm/os/log/logger.hpp>

namespace dm{
namespace os{
namespace protocol{

static const char* logModule = "CProtocolControlor.protocol.os.dm";

CProtocolControlor::CProtocolControlor( com::ios_t& ios ):
		m_dev(0),m_autoConnect(true),m_autoConnectDelay(5),m_autoConnectDelayTimes(0),m_autoConnectDelayDelta(5),m_autoConnectDelayMaxTimes(11),
		m_connectCnt(0),m_connectCntMax(0),
		m_txBufSending(0),m_txBuf1(),m_txBuf2(),m_rxBuf(),m_timer(ios),m_protocol(0),m_flags(0){
	log().debug(THISMODULE "创建对象");

	m_timer.sig_timeout.connect(boost::bind(&CProtocolControlor::onTimeUp,this));
}

CProtocolControlor::~CProtocolControlor(){
	log().debug(THISMODULE "销毁对象");
	if( m_dev!=0 )
		delete m_dev;

	if( m_protocol!=0 )
		delete m_protocol;
}

bool CProtocolControlor::setProtocol( protocol_t* p ){
	log().debug(THISMODULE "设置规约");

	if( m_protocol!=0 )
		delete m_protocol;
	m_protocol = p;
	m_protocol->getRxFrame();
	m_protocol->getTxFrame();

	return true;
}

/**
 * 设置通信控制器的通信设备
 * @param dev
 */
void CProtocolControlor::setDevice( device_t* dev ){
	if( m_dev!=0 ){
		log().info(THISMODULE "控制器释放原有设备");
		device_t* pd = m_dev;
		m_dev = 0;
		delete pd;
	}

	m_dev = dev;
	if( m_dev!=0 ){
		log().debug(THISMODULE "控制器给新设备安装信号");
		m_dev->sig_connected.connect( boost::bind(&CProtocolControlor::onConnected,this) );
		m_dev->sig_connectFail.connect( boost::bind(&CProtocolControlor::onConnectedFail,this));
		m_dev->sig_disconnected.connect( boost::bind(&CProtocolControlor::onDisconnected,this) );
		m_dev->sig_disconnectFail.connect( boost::bind(&CProtocolControlor::onDisconnected,this));
		m_dev->sig_receiveFail.connect( boost::bind(&CProtocolControlor::onRxFail,this));
		m_dev->sig_received.connect( boost::bind(&CProtocolControlor::onRx,this,_1,_2));
		m_dev->sig_sendFail.connect( boost::bind(&CProtocolControlor::onTxFail,this) );
		m_dev->sig_sendSuccess.connect( boost::bind(&CProtocolControlor::onTxed,this));

		if( m_dev->getState()==m_dev->Connected )
			onConnected();
	}

	m_txBufSending = 0;
	m_txBuf1.reset();
	m_txBuf2.reset();
}

bool CProtocolControlor::isDeviceSetted()const{
	return m_dev!=0;
}

bool CProtocolControlor::openDevice(){
	if( m_dev!=0 )
		return m_dev->asynConnect();
	log().warnning(THISMODULE "未设置通信设备");
	return false;
}

bool CProtocolControlor::closeDevice(){
	if( m_dev!=0 )
		return m_dev->asynDisconnect();
	return true;
}

bool CProtocolControlor::onConnected(){
	log().debug(THISMODULE "设备连接");

	++m_connectCnt;

	if( m_protocol==0 ){
		log().warnning(THISMODULE "未设置处理的规约");
	}else{
		m_protocol->onLinkSettled(dm::CTimeStamp::cur(),dm::CRunTimeStamp::cur());
		m_timer.start_nseconds( m_protocol->getRefreshInterval());
		m_txBufSending = 0;
		m_txBuf1.reset();
		m_txBuf2.reset();
		m_rxPos = m_rxBuf.getPos();

		m_autoConnectDelayTimes = 0;
	}
	return true;
}

void CProtocolControlor::onConnectedFail(){
	if( m_connectCntMax>0 ){
		if( m_connectCnt>=m_connectCntMax ){
			log().error(THISMODULE "连接(%d)达到最大次数(%d)，设置退出标志",m_connectCnt,m_connectCntMax);
			setFlag_exit();
			return;
		}
	}

	if( isExiting()==false && m_autoConnect ){
		if( m_autoConnectDelayTimes<m_autoConnectDelayMaxTimes )
			++m_autoConnectDelayTimes;
		int delay = m_autoConnectDelay;
		if( m_autoConnectDelayDelta>0 && m_autoConnectDelayTimes>0 ){
			delay += m_autoConnectDelayDelta*m_autoConnectDelayTimes;
		}

		log().info(THISMODULE "过%d秒之后再去连接吧",delay);
		m_timer.start_seconds(delay);
	}else{
		log().debug(THISMODULE "设备连接失败,断开");
	}
}

void CProtocolControlor::onDisconnected(){
	sig_devDisconnected();

	if( m_protocol!=0 )
		m_protocol->onLinkClosed(dm::CTimeStamp::cur(),dm::CRunTimeStamp::cur());

	if( m_connectCntMax>0 ){
		if( m_connectCnt>=m_connectCntMax ){
			log().error(THISMODULE "连接(%d)达到最大次数(%d)，设置退出标志",m_connectCnt,m_connectCntMax);
			setFlag_exit();
			return;
		}
	}

	if(  isExiting()==false && m_autoConnect ){
		log().info(THISMODULE "设备连接被关闭,5秒后重连");
		m_timer.start_seconds(5);
	}
}

void CProtocolControlor::onRx( const dm::uint8* buf,const size_t& len ){
	if( m_protocol==0 ){
		log().warnning(THISMODULE "没有设置处理规约");
		return;
	}

	if( len<=0 ){
		log().warnning(THISMODULE "数据长度(%d)<=0",len);
		return;
	}

	if( len>=m_rxBuf.getSize() )
		log().warnning(THISMODULE "数据长度(%d)超出缓冲区长度(%d)",m_rxBuf.getSize(),len);

	m_rxBuf.push(buf,len);
	telegram().pushRaw(m_protocol->name(),buf,len);

	if( !m_rxBuf.getPos().isNoMoreThanACycle(m_rxPos) ){
		log().warnning(THISMODULE "reset rx pos, because rxbuf overflowed");
		m_rxPos = m_rxBuf.getPos();
		return;
	}

	pos_t p = m_rxPos;
	while( m_protocol->getRxFrame().decode( m_rxBuf,m_rxBuf.getPos(),m_rxPos,&(m_protocol->getTxFrame()) ) ){
		if( !m_protocol->filterRxFrame() ){
			dm::CTimeStamp ts = dm::CTimeStamp::cur();
			dm::CRunTimeStamp rts = dm::CRunTimeStamp::cur();

			dm::uint8 tmp[3072];
			size_t l = m_rxPos - p;
			if( l>=3072 )
				l = 3072;
			m_rxBuf.getDataAndMovePos(tmp,l,p);
			telegram().pushRx(m_protocol->name(),tmp,dm::uint(l));
			m_protocol->updateRecvTime(dm::uint32(l),rts);

			p = m_rxPos;

			switch( m_protocol->dealRxFrame(ts,rts) ){
			case protocol_t::Action_Nothing:
				break;
			case protocol_t::Action_ReTime:
				break;
			case protocol_t::Action_Send:
				m_protocol->getTxFrame().encode(txBuf());
				break;
			case protocol_t::Action_SendAndReTime:
				m_protocol->getTxFrame().encode(txBuf());
				break;
			case protocol_t::Action_CloseLink:
				m_dev->asynDisconnect();
				break;
			case protocol_t::Action_ResetBuf:
				m_rxPos = m_rxBuf.getPos();
				break;
			default:
				return;
			}

			if( sendFrame() )
				return;
		}
	}
}

/**
 * 接收失败
 * 往往是因为网络或通信设备故障
 */
void CProtocolControlor::onRxFail(){
	if( m_dev ){
		if( m_autoConnect ){
			if( m_dev->asynDisconnect() ){
				log().debug( THISMODULE "异步关闭");
				return;
			}else{
				log().debug( THISMODULE "关闭连接失败，重新打开");
				m_dev->handler_disconnect();
				openDevice();
			}
		}else{
			log().info(THISMODULE "不需要自动连接。删除设备");
			m_dev = 0;
			device_t* pd = m_dev;
			delete pd;
			onDisconnected();
		}
	}
}

/**
 * 发送失败
 */
void CProtocolControlor::onTxFail(){
	log().debug( THISMODULE "发送失败");
	if( m_dev ){
		if( m_autoConnect ){
			if( m_dev->asynDisconnect() ){
				log().debug( THISMODULE "异步关闭");
				return;
			}else{
				log().debug( THISMODULE "关闭连接失败，重新打开");
				m_dev->handler_disconnect();
				openDevice();
			}
		}else{
			delete m_dev;
			m_dev = 0;
			log().debug( THISMODULE "删除连接");
			onDisconnected();
		}
	}
}

/**
 * 发送成功
 */
void CProtocolControlor::onTxed(){
	if( m_txBufSending==1 ){
		// buf1发送完成
		m_protocol->updateSendTime(m_txBuf1.getLen(),dm::CRunTimeStamp::cur());
		telegram().pushTx(m_protocol->name(),m_txBuf1.getData(),m_txBuf1.getLen());
		m_txBuf1.reset();
		m_txBufSending = 0;
	}else if( m_txBufSending==2 ){
		// buf2发送完成
		m_protocol->updateSendTime(m_txBuf2.getLen(),dm::CRunTimeStamp::cur());
		telegram().pushTx(m_protocol->name(),m_txBuf2.getData(),m_txBuf2.getLen());
		m_txBuf2.reset();
		m_txBufSending = 0;
	}

	sendFrame();
}

/**
 * 定时刷新
 */
void CProtocolControlor::onTimeUp(){
	if( m_protocol==0 ){
		log().warnning(THISMODULE "未设置规约对象");
	}else if( m_dev && m_dev->getState()==device_t::Unconnected ){
		if( m_autoConnect ){
			if( openDevice() )
				log().debug(THISMODULE "自动连接设备");
			else
				log().debug(THISMODULE "自动连接设备失败");

			// 不要再启动定时器了，如果连接失败，会接收失败信号
		}
	}else if( m_dev ){
		if( txBuf().getLen()==0 ){
			dm::CTimeStamp ts = dm::CTimeStamp::cur();
			dm::CRunTimeStamp rts = dm::CRunTimeStamp::cur();

			switch( m_protocol->timedRefresh(ts,rts) ){
			case protocol_t::Action_Send:
			case protocol_t::Action_SendAndReTime:
				m_protocol->getTxFrame().encode(txBuf());
				break;
			case protocol_t::Action_CloseLink:
				log().info( THISMODULE "关闭连接");
				if( !m_dev->asynDisconnect() ){
					log().info( THISMODULE "关闭连接失败，直接调用断开处理函数");
					m_dev->handler_disconnect();
					return;
				}
				break;
			case protocol_t::Action_ResetBuf:
				log().info(THISMODULE "复位收发缓冲区");
				m_rxPos = m_rxBuf.getPos();
				break;
			case protocol_t::Action_Reset:
				log().info(THISMODULE "复位规约");
				m_rxPos = m_rxBuf.getPos();
				m_protocol->reset(ts,rts);
			default:
				break;
			}

			sendFrame();
		}

		m_timer.start_nseconds(m_protocol->getRefreshInterval());
	}
}

bool CProtocolControlor::isExiting()const{
	return (m_flags&0x01)!=0;
}

void CProtocolControlor::setFlag_exit(){
	m_flags |= 0x01;
}

bool CProtocolControlor::sendFrame(){
	if( m_dev==NULL ){
		log().warnning(THISMODULE "未设置设备");
		return false;
	}

	if( m_txBufSending!=0 ){
		// 当前正在发送
		return false;
	}else{
		if( m_txBuf1.getLen()>0 ){	// buf1可以发送
			m_txBufSending = 1;
			return m_dev->asynSend(m_txBuf1.getData(),m_txBuf1.getLen());
		}else if( m_txBuf2.getLen()>0 ){
			m_txBufSending = 2;
			return m_dev->asynSend(m_txBuf2.getData(),m_txBuf2.getLen());
		}
	}

	return false;
}

}
}
}
